home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / unix / tkUnixEmbed.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  29.5 KB  |  1,002 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkUnixEmbed.c --
  3.  *
  4.  *    This file contains platform-specific procedures for UNIX to provide
  5.  *    basic operations needed for application embedding (where one
  6.  *    application can use as its main window an internal window from
  7.  *    some other application).
  8.  *
  9.  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * SCCS: @(#) tkUnixEmbed.c 1.22 97/08/13 11:15:51
  15.  */
  16.  
  17. #include "tkInt.h"
  18. #include "tkUnixInt.h"
  19.  
  20. /*
  21.  * One of the following structures exists for each container in this
  22.  * application.  It keeps track of the container window and its
  23.  * associated embedded window.
  24.  */
  25.  
  26. typedef struct Container {
  27.     Window parent;            /* X's window id for the parent of
  28.                      * the pair (the container). */
  29.     Window parentRoot;            /* Id for the root window of parent's
  30.                      * screen. */
  31.     TkWindow *parentPtr;        /* Tk's information about the container,
  32.                      * or NULL if the container isn't
  33.                      * in this process. */
  34.     Window wrapper;            /* X's window id for the wrapper
  35.                      * window for the embedded window.
  36.                      * Starts off as None, but gets
  37.                      * filled in when the window is
  38.                      * eventually created. */
  39.     TkWindow *embeddedPtr;        /* Tk's information about the embedded
  40.                      * window, or NULL if the embedded
  41.                      * application isn't in this process.
  42.                      * Note that this is *not* the
  43.                      * same window as wrapper: wrapper is
  44.                      * the parent of embeddedPtr. */
  45.     struct Container *nextPtr;        /* Next in list of all containers in
  46.                      * this process. */
  47. } Container;
  48.  
  49. static Container *firstContainerPtr = NULL;
  50.                     /* First in list of all containers
  51.                      * managed by this process.  */
  52.  
  53. /*
  54.  * Prototypes for static procedures defined in this file:
  55.  */
  56.  
  57. static void        ContainerEventProc _ANSI_ARGS_((
  58.                 ClientData clientData, XEvent *eventPtr));
  59. static void        EmbeddedEventProc _ANSI_ARGS_((
  60.                 ClientData clientData, XEvent *eventPtr));
  61. static int        EmbedErrorProc _ANSI_ARGS_((ClientData clientData,
  62.                 XErrorEvent *errEventPtr));
  63. static void        EmbedFocusProc _ANSI_ARGS_((ClientData clientData,
  64.                 XEvent *eventPtr));
  65. static void        EmbedGeometryRequest _ANSI_ARGS_((
  66.                 Container * containerPtr, int width, int height));
  67. static void        EmbedSendConfigure _ANSI_ARGS_((
  68.                 Container *containerPtr));
  69. static void        EmbedStructureProc _ANSI_ARGS_((ClientData clientData,
  70.                 XEvent *eventPtr));
  71. static void        EmbedWindowDeleted _ANSI_ARGS_((TkWindow *winPtr));
  72.  
  73. /*
  74.  *----------------------------------------------------------------------
  75.  *
  76.  * TkpUseWindow --
  77.  *
  78.  *    This procedure causes a Tk window to use a given X window as
  79.  *    its parent window, rather than the root window for the screen.
  80.  *    It is invoked by an embedded application to specify the window
  81.  *    in which it is embedded.
  82.  *
  83.  * Results:
  84.  *    The return value is normally TCL_OK.  If an error occurs (such
  85.  *    as string not being a valid window spec), then the return value
  86.  *    is TCL_ERROR and an error message is left in interp->result if
  87.  *    interp is non-NULL.
  88.  *
  89.  * Side effects:
  90.  *    Changes the colormap and other visual information to match that
  91.  *    of the parent window given by "string".
  92.  *
  93.  *----------------------------------------------------------------------
  94.  */
  95.  
  96. int
  97. TkpUseWindow(interp, tkwin, string)
  98.     Tcl_Interp *interp;        /* If not NULL, used for error reporting
  99.                  * if string is bogus. */
  100.     Tk_Window tkwin;        /* Tk window that does not yet have an
  101.                  * associated X window. */
  102.     char *string;        /* String identifying an X window to use
  103.                  * for tkwin;  must be an integer value. */
  104. {
  105.     TkWindow *winPtr = (TkWindow *) tkwin;
  106.     int id, anyError;
  107.     Window parent;
  108.     Tk_ErrorHandler handler;
  109.     Container *containerPtr;
  110.     XWindowAttributes parentAtts;
  111.  
  112.     if (winPtr->window != None) {
  113.     panic("TkUseWindow: X window already assigned");
  114.     }
  115.     if (Tcl_GetInt(interp, string, &id) != TCL_OK) {
  116.     return TCL_ERROR;
  117.     }
  118.     parent = (Window) id;
  119.  
  120.     /*
  121.      * Tk sets the window colormap to the screen default colormap in
  122.      * tkWindow.c:AllocWindow. This doesn't work well for embedded
  123.      * windows. So we override the colormap and visual settings to be
  124.      * the same as the parent window (which is in the container app).
  125.      */
  126.  
  127.     anyError = 0;
  128.     handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
  129.         EmbedErrorProc, (ClientData) &anyError);
  130.     if (!XGetWindowAttributes(winPtr->display, parent, &parentAtts)) {
  131.         anyError =  1;
  132.     }
  133.     XSync(winPtr->display, False);
  134.     Tk_DeleteErrorHandler(handler);
  135.     if (anyError) {
  136.     if (interp != NULL) {
  137.         Tcl_AppendResult(interp, "couldn't create child of window \"",
  138.             string, "\"", (char *) NULL);
  139.     }
  140.     return TCL_ERROR;
  141.     }
  142.     Tk_SetWindowVisual(tkwin, parentAtts.visual, parentAtts.depth,
  143.         parentAtts.colormap);
  144.  
  145.     /*
  146.      * Create an event handler to clean up the Container structure when
  147.      * tkwin is eventually deleted.
  148.      */
  149.  
  150.     Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc,
  151.         (ClientData) winPtr);
  152.  
  153.     /*
  154.      * Save information about the container and the embedded window
  155.      * in a Container structure.  If there is already an existing
  156.      * Container structure, it means that both container and embedded
  157.      * app. are in the same process.
  158.      */
  159.  
  160.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  161.         containerPtr = containerPtr->nextPtr) {
  162.     if (containerPtr->parent == parent) {
  163.         winPtr->flags |= TK_BOTH_HALVES;
  164.         containerPtr->parentPtr->flags |= TK_BOTH_HALVES;
  165.         break;
  166.     }
  167.     }
  168.     if (containerPtr == NULL) {
  169.     containerPtr = (Container *) ckalloc(sizeof(Container));
  170.     containerPtr->parent = parent;
  171.     containerPtr->parentRoot = parentAtts.root;
  172.     containerPtr->parentPtr = NULL;
  173.     containerPtr->wrapper = None;
  174.     containerPtr->nextPtr = firstContainerPtr;
  175.     firstContainerPtr = containerPtr;
  176.     }
  177.     containerPtr->embeddedPtr = winPtr;
  178.     winPtr->flags |= TK_EMBEDDED;
  179.     return TCL_OK;
  180. }
  181.  
  182. /*
  183.  *----------------------------------------------------------------------
  184.  *
  185.  * TkpMakeWindow --
  186.  *
  187.  *    Create an actual window system window object based on the
  188.  *    current attributes of the specified TkWindow.
  189.  *
  190.  * Results:
  191.  *    Returns the handle to the new window, or None on failure.
  192.  *
  193.  * Side effects:
  194.  *    Creates a new X window.
  195.  *
  196.  *----------------------------------------------------------------------
  197.  */
  198.  
  199. Window
  200. TkpMakeWindow(winPtr, parent)
  201.     TkWindow *winPtr;        /* Tk's information about the window that
  202.                  * is to be instantiated. */
  203.     Window parent;        /* Window system token for the parent in
  204.                  * which the window is to be created. */
  205. {
  206.     Container *containerPtr;
  207.  
  208.     if (winPtr->flags & TK_EMBEDDED) {
  209.     /*
  210.      * This window is embedded.  Don't create the new window in the
  211.      * given parent; instead, create it as a child of the root window
  212.      * of the container's screen.  The window will get reparented
  213.      * into a wrapper window later.
  214.      */
  215.  
  216.     for (containerPtr = firstContainerPtr; ;
  217.         containerPtr = containerPtr->nextPtr) {
  218.         if (containerPtr == NULL) {
  219.         panic("TkMakeWindow couldn't find container for window");
  220.         }
  221.         if (containerPtr->embeddedPtr == winPtr) {
  222.         break;
  223.         }
  224.     }
  225.     parent = containerPtr->parentRoot;
  226.     }
  227.  
  228.     return XCreateWindow(winPtr->display, parent, winPtr->changes.x,
  229.         winPtr->changes.y, (unsigned) winPtr->changes.width,
  230.         (unsigned) winPtr->changes.height,
  231.         (unsigned) winPtr->changes.border_width, winPtr->depth,
  232.         InputOutput, winPtr->visual, winPtr->dirtyAtts,
  233.         &winPtr->atts);
  234. }
  235.  
  236. /*
  237.  *----------------------------------------------------------------------
  238.  *
  239.  * TkpMakeContainer --
  240.  *
  241.  *    This procedure is called to indicate that a particular window
  242.  *    will be a container for an embedded application.  This changes
  243.  *    certain aspects of the window's behavior, such as whether it
  244.  *    will receive events anymore.
  245.  *
  246.  * Results:
  247.  *    None.
  248.  *
  249.  * Side effects:
  250.  *    None.
  251.  *
  252.  *----------------------------------------------------------------------
  253.  */
  254.  
  255. void
  256. TkpMakeContainer(tkwin)
  257.     Tk_Window tkwin;        /* Token for a window that is about to
  258.                  * become a container. */
  259. {
  260.     TkWindow *winPtr = (TkWindow *) tkwin;
  261.     Container *containerPtr;
  262.  
  263.     /*
  264.      * Register the window as a container so that, for example, we can
  265.      * find out later if the embedded app. is in the same process.
  266.      */
  267.  
  268.     Tk_MakeWindowExist(tkwin);
  269.     containerPtr = (Container *) ckalloc(sizeof(Container));
  270.     containerPtr->parent = Tk_WindowId(tkwin);
  271.     containerPtr->parentRoot = RootWindowOfScreen(Tk_Screen(tkwin));
  272.     containerPtr->parentPtr = winPtr;
  273.     containerPtr->wrapper = None;
  274.     containerPtr->embeddedPtr = NULL;
  275.     containerPtr->nextPtr = firstContainerPtr;
  276.     firstContainerPtr = containerPtr;
  277.     winPtr->flags |= TK_CONTAINER;
  278.  
  279.     /*
  280.      * Request SubstructureNotify events so that we can find out when
  281.      * the embedded application creates its window or attempts to
  282.      * resize it.  Also watch Configure events on the container so that
  283.      * we can resize the child to match.
  284.      */
  285.  
  286.     winPtr->atts.event_mask |= SubstructureRedirectMask|SubstructureNotifyMask;
  287.     XSelectInput(winPtr->display, winPtr->window, winPtr->atts.event_mask);
  288.     Tk_CreateEventHandler(tkwin,
  289.         SubstructureNotifyMask|SubstructureRedirectMask,
  290.         ContainerEventProc, (ClientData) winPtr);
  291.     Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbedStructureProc,
  292.         (ClientData) containerPtr);
  293.     Tk_CreateEventHandler(tkwin, FocusChangeMask, EmbedFocusProc,
  294.         (ClientData) containerPtr);
  295. }
  296.  
  297. /*
  298.  *----------------------------------------------------------------------
  299.  *
  300.  * EmbedErrorProc --
  301.  *
  302.  *    This procedure is invoked if an error occurs while creating
  303.  *    an embedded window.
  304.  *
  305.  * Results:
  306.  *    Always returns 0 to indicate that the error has been properly
  307.  *    handled.
  308.  *
  309.  * Side effects:
  310.  *    The integer pointed to by the clientData argument is set to 1.
  311.  *
  312.  *----------------------------------------------------------------------
  313.  */
  314.  
  315. static int
  316. EmbedErrorProc(clientData, errEventPtr)
  317.     ClientData clientData;    /* Points to integer to set. */
  318.     XErrorEvent *errEventPtr;    /* Points to information about error
  319.                  * (not used). */
  320. {
  321.     int *iPtr = (int *) clientData;
  322.  
  323.     *iPtr = 1;
  324.     return 0;
  325. }
  326.  
  327. /*
  328.  *----------------------------------------------------------------------
  329.  *
  330.  * EmbeddedEventProc --
  331.  *
  332.  *    This procedure is invoked by the Tk event dispatcher when various
  333.  *    useful events are received for a window that is embedded in
  334.  *    another application.
  335.  *
  336.  * Results:
  337.  *    None.
  338.  *
  339.  * Side effects:
  340.  *    Our internal state gets cleaned up when an embedded window is
  341.  *    destroyed.
  342.  *
  343.  *----------------------------------------------------------------------
  344.  */
  345.  
  346. static void
  347. EmbeddedEventProc(clientData, eventPtr)
  348.     ClientData clientData;        /* Token for container window. */
  349.     XEvent *eventPtr;            /* ResizeRequest event. */
  350. {
  351.     TkWindow *winPtr = (TkWindow *) clientData;
  352.  
  353.     if (eventPtr->type == DestroyNotify) {
  354.     EmbedWindowDeleted(winPtr);
  355.     }
  356. }
  357.  
  358. /*
  359.  *----------------------------------------------------------------------
  360.  *
  361.  * ContainerEventProc --
  362.  *
  363.  *    This procedure is invoked by the Tk event dispatcher when various
  364.  *    useful events are received for the children of a container
  365.  *    window.  It forwards relevant information, such as geometry
  366.  *    requests, from the events into the container's application.
  367.  *
  368.  * Results:
  369.  *    None.
  370.  *
  371.  * Side effects:
  372.  *    Depends on the event.  For example, when ConfigureRequest events
  373.  *    occur, geometry information gets set for the container window.
  374.  *
  375.  *----------------------------------------------------------------------
  376.  */
  377.  
  378. static void
  379. ContainerEventProc(clientData, eventPtr)
  380.     ClientData clientData;        /* Token for container window. */
  381.     XEvent *eventPtr;            /* ResizeRequest event. */
  382. {
  383.     TkWindow *winPtr = (TkWindow *) clientData;
  384.     Container *containerPtr;
  385.     Tk_ErrorHandler errHandler;
  386.  
  387.     /*
  388.      * Ignore any X protocol errors that happen in this procedure
  389.      * (almost any operation could fail, for example, if the embedded
  390.      * application has deleted its window).
  391.      */
  392.  
  393.     errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
  394.         -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
  395.  
  396.     /*
  397.      * Find the Container structure associated with the parent window.
  398.      */
  399.  
  400.     for (containerPtr = firstContainerPtr;
  401.         containerPtr->parent != eventPtr->xmaprequest.parent;
  402.         containerPtr = containerPtr->nextPtr) {
  403.     if (containerPtr == NULL) {
  404.         panic("ContainerEventProc couldn't find Container record");
  405.     }
  406.     }
  407.  
  408.     if (eventPtr->type == CreateNotify) {
  409.     /*
  410.      * A new child window has been created in the container. Record
  411.      * its id in the Container structure (if more than one child is
  412.      * created, just remember the last one and ignore the earlier
  413.      * ones).  Also set the child's size to match the container.
  414.      */
  415.  
  416.     containerPtr->wrapper = eventPtr->xcreatewindow.window;
  417.     XMoveResizeWindow(eventPtr->xcreatewindow.display,
  418.         containerPtr->wrapper, 0, 0,
  419.         (unsigned int) Tk_Width(
  420.             (Tk_Window) containerPtr->parentPtr),
  421.         (unsigned int) Tk_Height(
  422.             (Tk_Window) containerPtr->parentPtr));
  423.     } else if (eventPtr->type == ConfigureRequest) {
  424.     if ((eventPtr->xconfigurerequest.x != 0)
  425.         || (eventPtr->xconfigurerequest.y != 0)) {
  426.         /*
  427.          * The embedded application is trying to move itself, which
  428.          * isn't legal.  At this point, the window hasn't actually
  429.          * moved, but we need to send it a ConfigureNotify event to
  430.          * let it know that its request has been denied.  If the
  431.          * embedded application was also trying to resize itself, a
  432.          * ConfigureNotify will be sent by the geometry management
  433.          * code below, so we don't need to do anything.  Otherwise,
  434.          * generate a synthetic event.
  435.          */
  436.  
  437.         if ((eventPtr->xconfigurerequest.width == winPtr->changes.width)
  438.             && (eventPtr->xconfigurerequest.height
  439.             == winPtr->changes.height)) {
  440.         EmbedSendConfigure(containerPtr);
  441.         }
  442.     }
  443.     EmbedGeometryRequest(containerPtr,
  444.         eventPtr->xconfigurerequest.width,
  445.         eventPtr->xconfigurerequest.height);
  446.     } else if (eventPtr->type == MapRequest) {
  447.     /*
  448.      * The embedded application's map request was ignored and simply
  449.      * passed on to us, so we have to map the window for it to appear
  450.      * on the screen.
  451.      */
  452.  
  453.     XMapWindow(eventPtr->xmaprequest.display,
  454.         eventPtr->xmaprequest.window);
  455.     } else if (eventPtr->type == DestroyNotify) {
  456.     /*
  457.      * The embedded application is gone.  Destroy the container window.
  458.      */
  459.  
  460.     Tk_DestroyWindow((Tk_Window) winPtr);
  461.     }
  462.     Tk_DeleteErrorHandler(errHandler);
  463. }
  464.  
  465. /*
  466.  *----------------------------------------------------------------------
  467.  *
  468.  * EmbedStructureProc --
  469.  *
  470.  *    This procedure is invoked by the Tk event dispatcher when
  471.  *    a container window owned by this application gets resized
  472.  *    (and also at several other times that we don't care about).
  473.  *    This procedure reflects the size change in the embedded
  474.  *    window that corresponds to the container.
  475.  *
  476.  * Results:
  477.  *    None.
  478.  *
  479.  * Side effects:
  480.  *    The embedded window gets resized to match the container.
  481.  *
  482.  *----------------------------------------------------------------------
  483.  */
  484.  
  485. static void
  486. EmbedStructureProc(clientData, eventPtr)
  487.     ClientData clientData;        /* Token for container window. */
  488.     XEvent *eventPtr;            /* ResizeRequest event. */
  489. {
  490.     Container *containerPtr = (Container *) clientData;
  491.     Tk_ErrorHandler errHandler;
  492.  
  493.     if (eventPtr->type == ConfigureNotify) {
  494.     if (containerPtr->wrapper != None) {
  495.         /*
  496.          * Ignore errors, since the embedded application could have
  497.          * deleted its window.
  498.          */
  499.  
  500.         errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
  501.             -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
  502.         XMoveResizeWindow(eventPtr->xconfigure.display,
  503.             containerPtr->wrapper, 0, 0,
  504.             (unsigned int) Tk_Width(
  505.                 (Tk_Window) containerPtr->parentPtr),
  506.             (unsigned int) Tk_Height(
  507.                 (Tk_Window) containerPtr->parentPtr));
  508.         Tk_DeleteErrorHandler(errHandler);
  509.     }
  510.     } else if (eventPtr->type == DestroyNotify) {
  511.     EmbedWindowDeleted(containerPtr->parentPtr);
  512.     }
  513. }
  514.  
  515. /*
  516.  *----------------------------------------------------------------------
  517.  *
  518.  * EmbedFocusProc --
  519.  *
  520.  *    This procedure is invoked by the Tk event dispatcher when
  521.  *    FocusIn and FocusOut events occur for a container window owned
  522.  *    by this application.  It is responsible for moving the focus
  523.  *    back and forth between a container application and an embedded
  524.  *    application.
  525.  *
  526.  * Results:
  527.  *    None.
  528.  *
  529.  * Side effects:
  530.  *    The X focus may change.
  531.  *
  532.  *----------------------------------------------------------------------
  533.  */
  534.  
  535. static void
  536. EmbedFocusProc(clientData, eventPtr)
  537.     ClientData clientData;        /* Token for container window. */
  538.     XEvent *eventPtr;            /* ResizeRequest event. */
  539. {
  540.     Container *containerPtr = (Container *) clientData;
  541.     Tk_ErrorHandler errHandler;
  542.     Display *display;
  543.  
  544.     display = Tk_Display(containerPtr->parentPtr);
  545.     if (eventPtr->type == FocusIn) {
  546.     /*
  547.      * The focus just arrived at the container.  Change the X focus
  548.      * to move it to the embedded application, if there is one. 
  549.      * Ignore X errors that occur during this operation (it's
  550.      * possible that the new focus window isn't mapped).
  551.      */
  552.     
  553.     if (containerPtr->wrapper != None) {
  554.         errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
  555.             -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
  556.         XSetInputFocus(display, containerPtr->wrapper, RevertToParent,
  557.             CurrentTime);
  558.         Tk_DeleteErrorHandler(errHandler);
  559.     }
  560.     }
  561. }
  562.  
  563. /*
  564.  *----------------------------------------------------------------------
  565.  *
  566.  * EmbedGeometryRequest --
  567.  *
  568.  *    This procedure is invoked when an embedded application requests
  569.  *    a particular size.  It processes the request (which may or may
  570.  *    not actually honor the request) and reflects the results back
  571.  *    to the embedded application.
  572.  *
  573.  * Results:
  574.  *    None.
  575.  *
  576.  * Side effects:
  577.  *    If we deny the child's size change request, a Configure event
  578.  *    is synthesized to let the child know how big it ought to be.
  579.  *    Events get processed while we're waiting for the geometry
  580.  *    managers to do their thing.
  581.  *
  582.  *----------------------------------------------------------------------
  583.  */
  584.  
  585. static void
  586. EmbedGeometryRequest(containerPtr, width, height)
  587.     Container *containerPtr;    /* Information about the embedding. */
  588.     int width, height;        /* Size that the child has requested. */
  589. {
  590.     TkWindow *winPtr = containerPtr->parentPtr;
  591.  
  592.     /*
  593.      * Forward the requested size into our geometry management hierarchy
  594.      * via the container window.  We need to send a Configure event back
  595.      * to the embedded application if we decide not to honor its
  596.      * request; to make this happen, process all idle event handlers
  597.      * synchronously here (so that the geometry managers have had a
  598.      * chance to do whatever they want to do), and if the window's size
  599.      * didn't change then generate a configure event.
  600.      */
  601.  
  602.     Tk_GeometryRequest((Tk_Window) winPtr, width, height);
  603.     while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {
  604.     /* Empty loop body. */
  605.     }
  606.     if ((winPtr->changes.width != width)
  607.         || (winPtr->changes.height != height)) {
  608.     EmbedSendConfigure(containerPtr);
  609.     }
  610. }
  611.  
  612. /*
  613.  *----------------------------------------------------------------------
  614.  *
  615.  * EmbedSendConfigure --
  616.  *
  617.  *    This procedure synthesizes a ConfigureNotify event to notify an
  618.  *    embedded application of its current size and location.  This
  619.  *    procedure is called when the embedded application made a
  620.  *    geometry request that we did not grant, so that the embedded
  621.  *    application knows that its geometry didn't change after all.
  622.  *
  623.  * Results:
  624.  *    None.
  625.  *
  626.  * Side effects:
  627.  *    None.
  628.  *
  629.  *----------------------------------------------------------------------
  630.  */
  631.  
  632. static void
  633. EmbedSendConfigure(containerPtr)
  634.     Container *containerPtr;    /* Information about the embedding. */
  635. {
  636.     TkWindow *winPtr = containerPtr->parentPtr;
  637.     XEvent event;
  638.  
  639.     event.xconfigure.type = ConfigureNotify;
  640.     event.xconfigure.serial =
  641.         LastKnownRequestProcessed(winPtr->display);
  642.     event.xconfigure.send_event = True;
  643.     event.xconfigure.display = winPtr->display;
  644.     event.xconfigure.event = containerPtr->wrapper;
  645.     event.xconfigure.window = containerPtr->wrapper;
  646.     event.xconfigure.x = 0;
  647.     event.xconfigure.y = 0;
  648.     event.xconfigure.width = winPtr->changes.width;
  649.     event.xconfigure.height = winPtr->changes.height;
  650.     event.xconfigure.above = None;
  651.     event.xconfigure.override_redirect = False;
  652.  
  653.     /*
  654.      * Note:  when sending the event below, the ButtonPressMask
  655.      * causes the event to be sent only to applications that have
  656.      * selected for ButtonPress events, which should be just the
  657.      * embedded application.
  658.      */
  659.  
  660.     XSendEvent(winPtr->display, containerPtr->wrapper, False,
  661.         0, &event);
  662.  
  663.     /*
  664.      * The following needs to be done if the embedded window is
  665.      * not in the same application as the container window.
  666.      */
  667.  
  668.     if (containerPtr->embeddedPtr == NULL) {
  669.     XMoveResizeWindow(winPtr->display, containerPtr->wrapper, 0, 0,
  670.         (unsigned int) winPtr->changes.width,
  671.         (unsigned int) winPtr->changes.height);
  672.     }
  673. }
  674.  
  675. /*
  676.  *----------------------------------------------------------------------
  677.  *
  678.  * TkpGetOtherWindow --
  679.  *
  680.  *    If both the container and embedded window are in the same
  681.  *    process, this procedure will return either one, given the other.
  682.  *
  683.  * Results:
  684.  *    If winPtr is a container, the return value is the token for the
  685.  *    embedded window, and vice versa.  If the "other" window isn't in
  686.  *    this process, NULL is returned.
  687.  *
  688.  * Side effects:
  689.  *    None.
  690.  *
  691.  *----------------------------------------------------------------------
  692.  */
  693.  
  694. TkWindow *
  695. TkpGetOtherWindow(winPtr)
  696.     TkWindow *winPtr;        /* Tk's structure for a container or
  697.                  * embedded window. */
  698. {
  699.     Container *containerPtr;
  700.  
  701.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  702.         containerPtr = containerPtr->nextPtr) {
  703.     if (containerPtr->embeddedPtr == winPtr) {
  704.         return containerPtr->parentPtr;
  705.     } else if (containerPtr->parentPtr == winPtr) {
  706.         return containerPtr->embeddedPtr;
  707.     }
  708.     }
  709.     panic("TkpGetOtherWindow couldn't find window");
  710.     return NULL;
  711. }
  712.  
  713. /*
  714.  *----------------------------------------------------------------------
  715.  *
  716.  * TkpRedirectKeyEvent --
  717.  *
  718.  *    This procedure is invoked when a key press or release event
  719.  *    arrives for an application that does not believe it owns the
  720.  *    input focus.  This can happen because of embedding; for example,
  721.  *    X can send an event to an embedded application when the real
  722.  *    focus window is in the container application and is an ancestor
  723.  *    of the container.  This procedure's job is to forward the event
  724.  *    back to the application where it really belongs.
  725.  *
  726.  * Results:
  727.  *    None.
  728.  *
  729.  * Side effects:
  730.  *    The event may get sent to a different application.
  731.  *
  732.  *----------------------------------------------------------------------
  733.  */
  734.  
  735. void
  736. TkpRedirectKeyEvent(winPtr, eventPtr)
  737.     TkWindow *winPtr;        /* Window to which the event was originally
  738.                  * reported. */
  739.     XEvent *eventPtr;        /* X event to redirect (should be KeyPress
  740.                  * or KeyRelease). */
  741. {
  742.     Container *containerPtr;
  743.     Window saved;
  744.  
  745.     /*
  746.      * First, find the top-level window corresponding to winPtr.
  747.      */
  748.  
  749.     while (1) {
  750.     if (winPtr == NULL) {
  751.         /*
  752.          * This window is being deleted.  This is too confusing a
  753.          * case to handle so discard the event.
  754.          */
  755.  
  756.         return;
  757.     }
  758.     if (winPtr->flags & TK_TOP_LEVEL) {
  759.         break;
  760.     }
  761.     winPtr = winPtr->parentPtr;
  762.     }
  763.  
  764.     if (winPtr->flags & TK_EMBEDDED) {
  765.     /*
  766.      * This application is embedded.  If we got a key event without
  767.      * officially having the focus, it means that the focus is
  768.      * really in the container, but the mouse was over the embedded
  769.      * application.  Send the event back to the container.
  770.      */
  771.  
  772.     for (containerPtr = firstContainerPtr;
  773.         containerPtr->embeddedPtr != winPtr;
  774.         containerPtr = containerPtr->nextPtr) {
  775.         /* Empty loop body. */
  776.     }
  777.     saved = eventPtr->xkey.window;
  778.     eventPtr->xkey.window = containerPtr->parent;
  779.     XSendEvent(eventPtr->xkey.display, eventPtr->xkey.window, False,
  780.         KeyPressMask|KeyReleaseMask, eventPtr);
  781.     eventPtr->xkey.window = saved;
  782.     }
  783. }
  784.  
  785. /*
  786.  *----------------------------------------------------------------------
  787.  *
  788.  * TkpClaimFocus --
  789.  *
  790.  *    This procedure is invoked when someone asks or the input focus
  791.  *    to be put on a window in an embedded application, but the
  792.  *    application doesn't currently have the focus.  It requests the
  793.  *    input focus from the container application.
  794.  *
  795.  * Results:
  796.  *    None.
  797.  *
  798.  * Side effects:
  799.  *    The input focus may change.
  800.  *
  801.  *----------------------------------------------------------------------
  802.  */
  803.  
  804. void
  805. TkpClaimFocus(topLevelPtr, force)
  806.     TkWindow *topLevelPtr;        /* Top-level window containing desired
  807.                      * focus window; should be embedded. */
  808.     int force;                /* One means that the container should
  809.                      * claim the focus if it doesn't
  810.                      * currently have it. */
  811. {
  812.     XEvent event;
  813.     Container *containerPtr;
  814.  
  815.     if (!(topLevelPtr->flags & TK_EMBEDDED)) {
  816.     return;
  817.     }
  818.  
  819.     for (containerPtr = firstContainerPtr;
  820.         containerPtr->embeddedPtr != topLevelPtr;
  821.         containerPtr = containerPtr->nextPtr) {
  822.     /* Empty loop body. */
  823.     }
  824.  
  825.     event.xfocus.type = FocusIn;
  826.     event.xfocus.serial = LastKnownRequestProcessed(topLevelPtr->display);
  827.     event.xfocus.send_event = 1;
  828.     event.xfocus.display = topLevelPtr->display;
  829.     event.xfocus.window = containerPtr->parent;
  830.     event.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
  831.     event.xfocus.detail = force;
  832.     XSendEvent(event.xfocus.display, event.xfocus.window, False, 0, &event);
  833. }
  834.  
  835. /*
  836.  *----------------------------------------------------------------------
  837.  *
  838.  * TkpTestembedCmd --
  839.  *
  840.  *    This procedure implements the "testembed" command.  It returns
  841.  *    some or all of the information in the list pointed to by
  842.  *    firstContainerPtr.
  843.  *
  844.  * Results:
  845.  *    A standard Tcl result.
  846.  *
  847.  * Side effects:
  848.  *    None.
  849.  *
  850.  *----------------------------------------------------------------------
  851.  */
  852.  
  853. int
  854. TkpTestembedCmd(clientData, interp, argc, argv)
  855.     ClientData clientData;        /* Main window for application. */
  856.     Tcl_Interp *interp;            /* Current interpreter. */
  857.     int argc;                /* Number of arguments. */
  858.     char **argv;            /* Argument strings. */
  859. {
  860.     int all;
  861.     Container *containerPtr;
  862.     Tcl_DString dString;
  863.     char buffer[50];
  864.  
  865.     if ((argc > 1) && (strcmp(argv[1], "all") == 0)) {
  866.     all = 1;
  867.     } else {
  868.     all = 0;
  869.     }
  870.     Tcl_DStringInit(&dString);
  871.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  872.         containerPtr = containerPtr->nextPtr) {
  873.     Tcl_DStringStartSublist(&dString);
  874.     if (containerPtr->parent == None) {
  875.         Tcl_DStringAppendElement(&dString, "");
  876.     } else {
  877.         if (all) {
  878.         sprintf(buffer, "0x%x", (int) containerPtr->parent);
  879.         Tcl_DStringAppendElement(&dString, buffer);
  880.         } else {
  881.         Tcl_DStringAppendElement(&dString, "XXX");
  882.         }
  883.     }
  884.     if (containerPtr->parentPtr == NULL) {
  885.         Tcl_DStringAppendElement(&dString, "");
  886.     } else {
  887.         Tcl_DStringAppendElement(&dString,
  888.             containerPtr->parentPtr->pathName);
  889.     }
  890.     if (containerPtr->wrapper == None) {
  891.         Tcl_DStringAppendElement(&dString, "");
  892.     } else {
  893.         if (all) {
  894.         sprintf(buffer, "0x%x", (int) containerPtr->wrapper);
  895.         Tcl_DStringAppendElement(&dString, buffer);
  896.         } else {
  897.         Tcl_DStringAppendElement(&dString, "XXX");
  898.         }
  899.     }
  900.     if (containerPtr->embeddedPtr == NULL) {
  901.         Tcl_DStringAppendElement(&dString, "");
  902.     } else {
  903.         Tcl_DStringAppendElement(&dString,
  904.             containerPtr->embeddedPtr->pathName);
  905.     }
  906.     Tcl_DStringEndSublist(&dString);
  907.     }
  908.     Tcl_DStringResult(interp, &dString);
  909.     return TCL_OK;
  910. }
  911.  
  912. /*
  913.  *----------------------------------------------------------------------
  914.  *
  915.  * EmbedWindowDeleted --
  916.  *
  917.  *    This procedure is invoked when a window involved in embedding
  918.  *    (as either the container or the embedded application) is
  919.  *    destroyed.  It cleans up the Container structure for the window.
  920.  *
  921.  * Results:
  922.  *    None.
  923.  *
  924.  * Side effects:
  925.  *    A Container structure may be freed.
  926.  *
  927.  *----------------------------------------------------------------------
  928.  */
  929.  
  930. static void
  931. EmbedWindowDeleted(winPtr)
  932.     TkWindow *winPtr;        /* Tk's information about window that
  933.                  * was deleted. */
  934. {
  935.     Container *containerPtr, *prevPtr;
  936.  
  937.     /*
  938.      * Find the Container structure for this window work.  Delete the
  939.      * information about the embedded application and free the container's
  940.      * record.
  941.      */
  942.  
  943.     prevPtr = NULL;
  944.     containerPtr = firstContainerPtr;
  945.     while (1) {
  946.     if (containerPtr->embeddedPtr == winPtr) {
  947.         containerPtr->wrapper = None;
  948.         containerPtr->embeddedPtr = NULL;
  949.         break;
  950.     }
  951.     if (containerPtr->parentPtr == winPtr) {
  952.         containerPtr->parentPtr = NULL;
  953.         break;
  954.     }
  955.     prevPtr = containerPtr;
  956.     containerPtr = containerPtr->nextPtr;
  957.     }
  958.     if ((containerPtr->embeddedPtr == NULL)
  959.         && (containerPtr->parentPtr == NULL)) {
  960.     if (prevPtr == NULL) {
  961.         firstContainerPtr = containerPtr->nextPtr;
  962.     } else {
  963.         prevPtr->nextPtr = containerPtr->nextPtr;
  964.     }
  965.     ckfree((char *) containerPtr);
  966.     }
  967. }
  968.  
  969. /*
  970.  *----------------------------------------------------------------------
  971.  *
  972.  * TkUnixContainerId --
  973.  *
  974.  *    Given an embedded window, this procedure returns the X window
  975.  *    identifier for the associated container window.
  976.  *
  977.  * Results:
  978.  *    The return value is the X window identifier for winPtr's
  979.  *    container window.
  980.  *
  981.  * Side effects:
  982.  *    None.
  983.  *
  984.  *----------------------------------------------------------------------
  985.  */
  986.  
  987. Window
  988. TkUnixContainerId(winPtr)
  989.     TkWindow *winPtr;        /* Tk's structure for an embedded window. */
  990. {
  991.     Container *containerPtr;
  992.  
  993.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  994.         containerPtr = containerPtr->nextPtr) {
  995.     if (containerPtr->embeddedPtr == winPtr) {
  996.         return containerPtr->parent;
  997.     }
  998.     }
  999.     panic("TkUnixContainerId couldn't find window");
  1000.     return None;
  1001. }
  1002.